package com.linkhub.oms.admin.modules.logistic.freighttemplate.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import com.linkhub.oms.admin.common.exception.ExceptionFactory;
import com.linkhub.oms.admin.modules.logistic.freighttemplate.domain.dto.LogisticFreightCalculateDTO;
import com.linkhub.oms.admin.modules.logistic.freighttemplate.domain.vo.LogisticFreightCalculateVO;
import com.linkhub.oms.admin.modules.logistic.freighttemplate.service.LogisticFreightBsService;
import com.linkhub.oms.common.util.QtBigDecimalUtil;
import com.linkhub.oms.common.util.QtStreamUtil;
import com.linkhub.oms.common.util.json.QtFastjsonUtil;
import com.linkhub.oms.dao.mpservice.ICountryPartitionService;
import com.linkhub.oms.dao.mpservice.ILogisticFreightTemplateDetailService;
import com.linkhub.oms.dao.mpservice.ILogisticFreightTemplateService;
import com.linkhub.oms.entity.CountryPartitionEntity;
import com.linkhub.oms.entity.LogisticFreightTemplateDetailEntity;
import com.linkhub.oms.entity.LogisticFreightTemplateEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 物流运费 服务类
 * </p>
 *
 * @author Frank
 */
@Service
@Slf4j
@Validated
public class LogisticFreightBsServiceImpl implements LogisticFreightBsService {
    @Resource
    private ILogisticFreightTemplateService logisticFreightTemplateService;
    @Resource
    private ILogisticFreightTemplateDetailService logisticFreightTemplateDetailService;
    @Resource
    private ICountryPartitionService countryPartitionService;


    @Override
    public LogisticFreightCalculateVO calculateFreight(LogisticFreightCalculateDTO logisticFreightCalculateDTO) {
        log.info("运费计算,data:{}", QtFastjsonUtil.toJSONString(logisticFreightCalculateDTO));
        LocalDateTime calDate = logisticFreightCalculateDTO.getCalDate();

        String channelCode = logisticFreightCalculateDTO.getChannelCode();
        String countryCode = logisticFreightCalculateDTO.getCountryCode();
        List<LogisticFreightTemplateEntity> freightTemplateEntityList = logisticFreightTemplateService.listByChanelAndCountryAndDate(channelCode,
                countryCode,
                calDate);
        if (CollUtil.isEmpty(freightTemplateEntityList)) {
            throw ExceptionFactory.getI18nBizException("freight.template.does.not.exist");
        }

        //校验国家分区
        List<CountryPartitionEntity> countryPartitionEntities = countryPartitionService.listByCountryCode(countryCode);
        boolean hasCountryPartition = QtStreamUtil.anyMatch(countryPartitionEntities,
                countryPartitionEntity -> StringUtils.isNotBlank(countryPartitionEntity.getCountryPartition()) &&
                        CollUtil.isNotEmpty(countryPartitionEntity.getPostCode()));
        String postCode = logisticFreightCalculateDTO.getPostCode();
        if (hasCountryPartition && StringUtils.isBlank(postCode)) {
            //国家有分区，必须要传邮编
            throw ExceptionFactory.getI18nBizException("freight.template.unavailable");
        }
        //匹配运费模板
        LogisticFreightTemplateEntity logisticFreightTemplateEntity = matchFreightTemplate(freightTemplateEntityList,
                countryPartitionEntities,
                hasCountryPartition,
                postCode);
        log.info("匹配的运费模板：{}", logisticFreightTemplateEntity.getTemplateName());

        List<LogisticFreightTemplateDetailEntity> freightTemplateDetailEntities =
                logisticFreightTemplateDetailService.listByFreightTemplateId(logisticFreightTemplateEntity.getId());
        if (CollUtil.isEmpty(freightTemplateDetailEntities)) {
            //没有重量区间
            throw ExceptionFactory.getI18nBizException("freight.template.weight.unavailable");
        }

        //计算最终重量
        BigDecimal dynamicWeight = logisticFreightCalculateDTO.getDynamicWeight();
        BigDecimal packageWeightLast = logisticFreightCalculateDTO.getPackageWeight().add(dynamicWeight);
        BigDecimal weightLast = calculateLastWeight(logisticFreightCalculateDTO,
                logisticFreightTemplateEntity,
                dynamicWeight,
                packageWeightLast);
        log.info("最终重量weightLast：{}", weightLast);
        LogisticFreightTemplateDetailEntity freightTemplateDetailEntity = QtStreamUtil.findFirst(freightTemplateDetailEntities,
                detailEntity -> QtBigDecimalUtil.gt(weightLast, detailEntity.getStartingWeight()) &&
                        QtBigDecimalUtil.le(weightLast, detailEntity.getEndingWeight()));
        if (Objects.isNull(freightTemplateDetailEntity)) {
            //没有匹配的重量区间
            throw ExceptionFactory.getI18nBizException("freight.template.weight.unavailable");
        }
        log.info("匹配的重量区间，StartingWeight：{}，EndingWeight：{}", freightTemplateDetailEntity.getStartingWeight(),
                freightTemplateDetailEntity.getEndingWeight());
        return calculateFreight(logisticFreightTemplateEntity, weightLast, freightTemplateDetailEntity);
    }

    /**
     * 匹配运费模板
     */
    private LogisticFreightTemplateEntity matchFreightTemplate(List<LogisticFreightTemplateEntity> freightTemplateEntityList,
                                                               List<CountryPartitionEntity> countryPartitionEntities,
                                                               boolean hasCountryPartition,
                                                               String postCode) {
        if (hasCountryPartition) {
            CountryPartitionEntity entity = QtStreamUtil.findFirst(countryPartitionEntities,
                    countryPartitionEntity ->
                            StringUtils.isNotBlank(countryPartitionEntity.getCountryPartition()) &&
                                    CollUtil.isNotEmpty(countryPartitionEntity.getPostCode()) &&
                                    countryPartitionEntity.getPostCode().contains(postCode));
            if (Objects.isNull(entity)) {
                //国家有分区，但传的邮编不在该国家的配置表里
                throw ExceptionFactory.getI18nBizException("freight.template.unavailable");
            }
            LogisticFreightTemplateEntity logisticFreightTemplateEntity = QtStreamUtil.findFirst(freightTemplateEntityList,
                    freightTemplateEntity -> Objects.equals(entity.getCountryPartition(), freightTemplateEntity.getCountryPartition()));
            if (Objects.isNull(logisticFreightTemplateEntity)) {
                //没有该分区的运费模板
                throw ExceptionFactory.getI18nBizException("freight.template.unavailable");
            }
            return logisticFreightTemplateEntity;
        }
        //取最先配置的有效运费模板
        return freightTemplateEntityList.get(0);
    }

    /**
     * 运费计算
     */
    private LogisticFreightCalculateVO calculateFreight(LogisticFreightTemplateEntity logisticFreightTemplateEntity,
                                                        BigDecimal weightLast,
                                                        LogisticFreightTemplateDetailEntity freightTemplateDetailEntity) {
        LogisticFreightCalculateVO freightCalculateVO = new LogisticFreightCalculateVO();
        freightCalculateVO.setActualFeeCurrencyType(logisticFreightTemplateEntity.getActualFeeCurrencyType());

        //对外运费=最终重量(g)*对应重量段对外运费价格/1000 默认两位⼩数 四舍五⼊
        BigDecimal externalFreightLast = weightLast
                .multiply(freightTemplateDetailEntity.getExternalFreight())
                .divide(QtBigDecimalUtil.BD_1000, 2, RoundingMode.HALF_UP);

        //实际成本运费=最终重量(g)*对应重量段实际运费价格/1000	  默认两位⼩数 四舍五⼊
        BigDecimal actualFreightLast = weightLast
                .multiply(freightTemplateDetailEntity.getActualFreight())
                .divide(QtBigDecimalUtil.BD_1000, 2, RoundingMode.HALF_UP);

        freightCalculateVO.setExternalFreight(externalFreightLast);
        freightCalculateVO.setActualFreight(actualFreightLast);
        freightCalculateVO.setExternalRegistrationFee(freightTemplateDetailEntity.getExternalRegistrationFee());
        freightCalculateVO.setActualRegistrationFee(freightTemplateDetailEntity.getActualRegistrationFee());
        log.info("最终运费计算结果：{}", QtFastjsonUtil.toJSONString(freightCalculateVO));
        return freightCalculateVO;
    }

    /**
     * 计算最终重量  后续这边要加上模板的进位方式的处理
     */
    private BigDecimal calculateLastWeight(LogisticFreightCalculateDTO logisticFreightCalculateDTO,
                                           LogisticFreightTemplateEntity logisticFreightTemplateEntity,
                                           BigDecimal dynamicWeight,
                                           BigDecimal packageWeightLast) {
        BigDecimal volumeWeight = logisticFreightCalculateDTO.getVolumeWeight();
        BigDecimal volumeWeightLast = volumeWeight;
        Integer bubbleCoefficient = logisticFreightTemplateEntity.getBubbleCoefficient();
        if (bubbleCoefficient <= 0) {
            throw ExceptionFactory.getI18nBizException("freight.template.bubble.coefficient.invalid");
        }
        if (QtBigDecimalUtil.gt(volumeWeightLast, BigDecimal.ZERO)) {
            //体积重=总体积/计泡系数*1000 + 动态重量
            volumeWeightLast = volumeWeight
                    .multiply(QtBigDecimalUtil.BD_1000)
                    .divide(new BigDecimal(bubbleCoefficient), 16, RoundingMode.HALF_UP)
                    .add(dynamicWeight);
        }
        //最低计费重=最低计费重（模板） + 动态重量
        BigDecimal minimumChargeableWeightLast = logisticFreightTemplateEntity.getMinimumChargeableWeight().add(dynamicWeight);

        List<BigDecimal> allWeight = Lists.newArrayList(volumeWeightLast, packageWeightLast, minimumChargeableWeightLast);
        //最终重量=max(订单体积重,包裹重,最低计费重)
        return Collections.max(allWeight);
    }
}
